//
//  MyServer.m
//  server100
//
//  Created by 孙晓晔 on 2017/5/16.
//  Copyright © 2017年 孙晓晔. All rights reserved.
//

#import "MyServer.h"

#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>

@interface MyServer()

@property(nonatomic,assign) int serverSocket; // 服务端socket

@property(nonatomic,strong) NSMutableArray *msg;

@property(nonatomic,assign) BOOL isUpdated;

@end

@implementation MyServer

-(instancetype)initWithPort:(int)port  {
    self = [super init];
    if (self) {
        self.port = port;
    }
    
    return self;
}

// 懒加载
-(NSMutableArray *)clientSockets {
    if (_clientSockets == nil) {
        
       _clientSockets  = [NSMutableArray array];
    }
    
    return _clientSockets;
}

// 懒加载
-(NSMutableArray *)msg {
    if (_msg == nil) {
        
        _msg  = [NSMutableArray array];
    }
    
    return _msg;
}

// 在新线程中监听客户端
-(void)startListenAndNewThread {
    
    self.isOpen = NO;
    
    dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    dispatch_async(queue1, ^{
        
        [self initServer];
    });
    
    [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateUserList) userInfo:nil repeats:YES];
}

-(void)updateUserList {
    if (!self.isOpen) {
        return;
    }
    
    if (!self.isUpdated) {
        return;
    }
    
    const char *list = [self data2json:self.clientSockets];
    
    for(NSDictionary *key in self.clientSockets) {
        NSString *from = [key objectForKey:@"id"];
        
        ssize_t ret = send([from intValue], list, 1024, 0);
        if (ret > 0) {
            NSLog(@"发送用户列表成功", nil);
        }
    }
    
    self.isUpdated = FALSE;
}

-(void)initServer {
    
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        [self log:@"创建socket失败"];
        return;
    }
    
    [self log:@"创建socket成功"];
    
    self.serverSocket = serverSocket;
    
    struct sockaddr_in server_addr;
    
    server_addr.sin_len = sizeof(struct sockaddr_in);
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(self.port);
    server_addr.sin_addr.s_addr = htons(INADDR_ANY);
    bzero(&(server_addr.sin_zero), 8);
    
    int ret = bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1) {
        [self log:@"绑定端口失败"];
        return;
    }
    
    [self log:@"绑定端口成功"];
    
    if (listen(serverSocket, 5) == -1) {
        [self log:@"端口监听失败"];
        return;
    }
    
    self.isOpen = TRUE;
    [self log:@"服务启动"];
    
    while(1) {
        [self log:@"等待客户端连接..."];
        
        struct sockaddr_in client_address;
        socklen_t address_len;
        
        int clientSocket = accept(serverSocket, (struct sockaddr *)&client_address, &address_len);
        if (clientSocket == -1) {
            [self log:@"客户端连接失败"];
            close(clientSocket);
            return;
        }
        
        [self log:[[NSString alloc] initWithFormat:@"新客户端 = %d, 已连接...", clientSocket]];
        
        dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        dispatch_async(queue1, ^{
            [self recv:clientSocket];
        });
    }
}

-(void)log:(NSString*)str {
    NSLog(@"%@", str);
}

// 输出用户列表
-(NSString*)userList {
    
    NSString *ret = @"";
    
    for (NSDictionary *dic in self.clientSockets) {
        NSString *key = [dic objectForKey:@"id"];
        NSString *nickname = [dic objectForKey:@"name"];
        ret = [ret stringByAppendingFormat:@"%@ = %@\n", key, nickname];
    }
    
    return ret;
}

// 接受数据
-(void)recv:(int)clientSocket {
    
    while(1) {
        char buf[1024];
        bzero(buf, 1024);
        
        ssize_t ret = recv(clientSocket, buf, 1024, 0);
        if (ret <= 0) {
            [self logout:clientSocket];
            break;
        }
        
        if (ret > 0) {
            printf("recv:%s\n", buf);
            
            NSData *jsonData = [NSData dataWithBytes:buf length:strlen(buf)];
            
            NSError *err;
            NSMutableDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
            
            if (err) {
                NSLog(@"数据包解析出错");
                continue;
            }
            
            [self parse:clientSocket dic:dic];
        }
    }
}

// 退出
-(void)logout:(int)clientSocket {
    [self removeClient:clientSocket];
    
    self.isUpdated = TRUE;
}

-(const char*)data2json:(id)object {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:object options:NSJSONWritingPrettyPrinted error:&error];
    
    if (error) {
        NSLog(@"Got an error: %@", error);
        return nil;
    }
    
    NSString *str = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    
    return [str cStringUsingEncoding:NSUTF8StringEncoding];
    
//    return [jsonData bytes];
}

// 解析数据
-(void)parse:(int)clientSocket dic:(NSMutableDictionary*)dic {
    
    NSString *type = [dic valueForKey:@"type"];
    NSString *to = [dic valueForKey:@"to"];
    
    NSString *from = [NSString stringWithFormat:@"%d", clientSocket];
    [dic setValue:from forKey:@"from"];
    
    const char *buf = [self data2json:dic];
    
    NSLog(@"%@", type);
    
    if ([type isEqualToString:@"login"]) {
        NSString *nickname = [dic objectForKey:@"nickname"];
        
        NSMutableDictionary *client = [NSMutableDictionary dictionary];
        [client setValue:from forKey:@"id"];
        [client setValue:nickname forKey:@"name"];
        
        [self.clientSockets addObject:client];
        
        self.isUpdated = TRUE;
        
    } else if ([type isEqualToString:@"logout"]) {
        
        [self removeClient:clientSocket];
        
        self.isUpdated = TRUE;
        
    } else if ([type isEqualToString:@"chat"]) {
        [self addMsg:dic];
        
        if ([to isEqualToString:@""]) {
            return;
        }
        
        int socket = [to intValue];
        ssize_t ret = send(socket, buf, 1024, 0);
        if (ret > 0) {
            NSLog(@"发送成功", nil);
        }
    }
}

-(void)addMsg:(NSDictionary*)dic {
    
    [self.msg addObject:dic];
    
    if (self.msg.count > 20) {
        [self.msg removeObjectAtIndex:0];
    }
}

-(NSString*)msgList {
    
    NSString *ret = @"";
    
    for(int i = self.msg.count - 1; i >= 0; i--) {
        NSDictionary *dic = self.msg[i];
        
        NSString *from = [dic objectForKey:@"from"];
        NSString *to = [dic objectForKey:@"to"];
        NSString *body = [dic objectForKey:@"body"];
        
        ret = [ret stringByAppendingFormat:@"%@ %@ %@\n", from, to, body];
    }
    
    return ret;
}

// 删除已断开的客户端
-(void)removeClient:(int)clientSocket {
    
    close(clientSocket);
    
    NSString *str = [NSString stringWithFormat:@"%d", clientSocket];
    
    for (NSDictionary *dic in self.clientSockets) {
        
        NSString *from = [dic objectForKey:@"id"];
        if ([from isEqualToString:str]) {
            [self.clientSockets removeObject:dic];
            return;
        }
    }
}

// 发送数据
-(void)send:(NSString*)str {
    NSLog(@"发送数据", nil);
    
    [self chat:@"" body:str];
}

// 群发
-(void)chat:(NSString*)to body:(NSString*)body {
    
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    
    [dic setValue:@"chat" forKey:@"type"];
    [dic setValue:[NSString stringWithFormat:@"%d", self.serverSocket] forKey:@"from"];
    [dic setValue:to forKey:@"to"];
    [dic setValue:body forKey:@"body"];
    
    [self.msg addObject:dic];
    
    const char *buf = [self data2json:dic];
    
    if (buf == nil) {
        NSLog(@"数据有误", nil);
        return;
    }
    
    for(NSDictionary *key in self.clientSockets) {
        int socket = [[key objectForKey:@"id"] intValue];
        
        ssize_t ret = send(socket, buf, 1024, 0);
        if (ret > 0) {
            NSLog(@"发送成功", nil);
        }
    }
}

-(void)close {
    NSLog(@"服务停止", nil);
    
    self.isOpen = FALSE;
    
    for(NSDictionary *key in self.clientSockets) {
        NSString *from = [key objectForKey:@"id"];
        
        close([from intValue]);
    }
    
    close(self.serverSocket);
}

@end
